home *** CD-ROM | disk | FTP | other *** search
- #ifndef FWCHARIT_H
- #define FWCHARIT_H
- //========================================================================================
- //
- // File: FWCharIt.h
- // Release Version: $ 1.0d1 $
- //
- // Creation Date: 3/28/94
- //
- // Copyright: © 1994 by Apple Computer, Inc., all rights reserved.
- //
- //========================================================================================
-
- #ifndef FWEXCDEF_H
- #include "FWExcDef.h"
- #endif
-
- #ifndef FWMATH_H
- #include "FWMath.h"
- #endif
-
- #ifndef FWPRIDEB_H
- #include "FWPriDeb.h"
- #endif
-
- #ifndef FWCHARAC_H
- #include "FWCharac.h"
- #endif
-
- #define FW_DEBUG_TEXT_ITERATORS
-
-
- //========================================================================================
- // Design Notes for Text Readers
- //
- // Text readers are designed to be as fast and light-weight as possible. We assume
- // that in over 90% of the usage of Text readers, the reader will be used to make
- // one sequential pass through the data structure, operating on one character at a time.
- // The first design goal is therefore:
- // 1) Make GetCharacterAndAdvance be as efficient as possible.
- // In order to achieve full efficiency, we need to minimize overhead for error checking
- // for reading past the end of the data structure. We therefore set this requirement:
- // 2) Rely on a clear contract to minimize overhead. It is not necessary for
- // iterators to fail gracefully when misused.
- // As stated above, in 90% of the cases, the text is read in one forward pass. However,
- // reading backward through the text is a surprisingly large portion of the remaining
- // 10%, and if not supported, significantly reduces the usefulness of readers. We
- // therefore attempt to achieve this goal:
- // 3) Make "put back" a relatively efficient operation. Make it possible to
- // read backwards through the data structure.
- // Often a client iterating over text will want to note the position of some character
- // or token in the text. We therefore set another goal:
- // 4) Support GetPosition ('tell') and SetPosition ('seek') operations.
- // This last goal implies a specific need to handle the case where a client attempts to
- // seek past the end of the text data structure. In this case, to achieve efficiency,
- // we invoke 2), by setting this requirement:
- // 5) It is acceptable to state in the contract that an attempt to SetPosition to
- // an arbitrary position may fail. However, a client can use GetLength to find
- // the length of the data structure; it is safe to SetPosition to any value greater
- // than or equal to zero, and less than the length of the data structure.
- //========================================================================================
-
- //========================================================================================
- // CLASS FW_CTextReader
- //
- // A base class for iterators that read over a data structure containing characters.
- //
- // It is possible to create a TextReader to read over any text data structure, as long
- // as the following constraints are met:
- //
- // 1) It must be possible to get the total number of characters in the data structure
- // at the time the text reader is constructed.
- // 1a) Of course, we assume that the length and content of the data structure does
- // not change while the iterator is being used!
- // 2) The data members fStart, fLimit, and fNext are updated
- //
- //
- // Invariant:
- // ((fStart<=fNext) && (fNext<fLimit))
- // || ((fStart-1==fNext) && (fBufferSum==0))
- // || ((fNext==fLimit) && (fBufferSum==GetLength())
- //========================================================================================
-
- class FW_CTextReader : public _FW_CAutoDestructObject
- {
-
- public:
-
- // ----- General
-
- ~FW_CTextReader();
- FW_CTextReader(const FW_Byte *chunk1Start, // start of first contiguous chunk
- const FW_Byte *chunk1Limit, // limit of first contiguous chunk
- FW_CharacterCount totalLength);// total characters in data structure
-
- FW_CharacterCount GetPosition();
- // Get the current position, where 0 is first character in data structure.
-
- void SetPosition(FW_CharacterCount position);
- // Set the position to position.
- // The result is undefined if position is outside the bounds of the data structure.
-
- FW_CharacterCount GetLength();
- // Get number of characters in data structure.
-
- // ----- Character-by-character iteration
-
- void Advance();
- // Advance by one character.
-
- void Backup();
- // Backup by one character.
-
- FW_Char PeekCharacter();
- // Return the current character without advancing. Can be used for lookahead.
-
- FW_Char GetCharacterAndAdvance();
- // Get the current character and advance.
-
- FW_Char BackupAndGetCharacter();
- // Backup and get previous character.
-
- // ----- Chunky iteration
- // With chunky iteration, client is responsible for translating between bytes and characters.
- // The static member functions FW_CharactersInBlock
- // and FW_CString::BytesInString may be used to do the translation.
-
- void Advance(FW_CharacterCount delta);
- // Advance by delta characters.
-
- void Backup(FW_CharacterCount delta);
- // Backup by delta characters.
-
- void PeekRunAhead(const FW_Byte*& start, FW_ByteCount& length);
- // Peek ahead into current buffer of bytes
- // Use Advance(delta) to inform iterator of number of characters consumed
-
- void PeekRunBehind(const FW_Byte*& end, FW_ByteCount& length);
- // Peek behind into current buffer of bytes
- // end points one past "current" byte!
- // Use Backup(delta) to inform iterator of number of characters consumed
-
- protected:
-
- void GetNextBuffer();
- // Calls DoGetNextBuffer, and updates fNext, fBufferSum.
-
- void GetPreviousBuffer();
- // Calls DoGetPreviousBuffer, and updates fNext, fBufferSum.
-
- virtual void DoGetNextBuffer() = 0;
- // Get another buffer from text data structure.
- // Updates fStart and fLimit.
- // Must ensure that fStart<=fLimit.
-
- virtual void DoGetPreviousBuffer() = 0;
- // Gets previous buffer from text data structure.
- // Updates fStart and fLimit.
- // Must ensure that fStart<=fLimit.
-
- const FW_Byte *fStart; // Start of current buffer
-
- const FW_Byte *fLimit; // One past last character of current buffer
-
- FW_CharacterCount fLength; // Total characters in data structure.
-
- private:
-
- const FW_Byte *fNext; // Current position in buffer
-
- #ifdef FW_DEBUG_TEXT_ITERATORS
- void ClassInvariants();
- #else
- void ClassInvariants() {} // Let compiler optimize away the empty inline
- #endif
-
- FW_CharacterCount fBufferSum; // Total characters in previous buffers.
- };
-
- //========================================================================================
- // CLASS FW_CTextWriter
- //
- // TextWriters are (intentionally) kept simpler than TextReaders. We assume that there
- // is no need to allow backing up in order to rewrite. This results in a smaller and
- // simpler interface.
- //========================================================================================
-
- enum FW_TextWriterMode {FW_kTextWriteOver, FW_kTextAppend};
-
- class FW_CTextWriter : public _FW_CAutoDestructObject
- {
- public:
-
- // ----- General
-
- virtual ~FW_CTextWriter();
- // Flush the current buffer.
- // Writer destructors must do whatever may be necessary to restore text structure
- // to valid state, e.g. restore NUL termination, cached length member, etc.
-
- FW_CTextWriter(FW_Byte *chunk1Start, // start of first contiguous chunk
- FW_Byte *chunk1Limit);// limit of first contiguous chunk
-
- FW_CharacterCount GetPosition();
- // Get the current position.
-
- // ----- Character-by-character iteration
-
- void PutCharacterAndAdvance(FW_Char character);
- // Write the character into the data structure and advance to next position.
-
- // ----- Chunky iteration
-
- void WritePeek(FW_Byte*& start, FW_ByteCount& length);
- // Returns start address and length of buffer to write into.
-
- void WritePeekAdvance(FW_Byte * const start, FW_ByteCount bytesWritten);
- // Inform iterator of number of bytes written into peek buffer
- // start value must be same as returned by WritePeek
- // No calls to PutCharacterAndAdvance between WritePeek and WritePeekAdvance!
-
- protected:
-
- virtual void DoFlushAndGetNextBuffer() = 0;
- // Flush the current buffer.
- // Get another buffer from text data structure, update fNext and fLimit.
-
- void FlushAndGetNextBuffer();
- // Calls DoFlushAndGetNextBuffer and updates fBufferSum.
-
- FW_CharacterCount fBufferSum; // Total characters flushed in previous buffers.
- FW_Byte *fStart; // First byte in this buffer
- FW_Byte *fLimit; // One past last byte of current buffer
- FW_Byte *fNext; // Current position in buffer
- };
-
- //========================================================================================
- // CLASS FW_CMemoryReader
- //
- // A class for iterating over a buffer of characters.
- //========================================================================================
-
- class FW_CMemoryReader : public FW_CTextReader
- {
- public:
-
- ~FW_CMemoryReader();
- FW_CMemoryReader(const FW_Byte * buffer, FW_ByteCount bytes);
- FW_CMemoryReader(const FW_Char * buffer, FW_CharacterCount characters);
-
- protected:
-
- virtual void DoGetNextBuffer();
- virtual void DoGetPreviousBuffer();
-
- };
-
- //========================================================================================
- // CLASS FW_CMemoryWriter
- //
- // A class for writing into a buffer of characters.
- //========================================================================================
-
- class FW_CMemoryWriter : public FW_CTextWriter
- {
- public:
-
- ~FW_CMemoryWriter();
- FW_CMemoryWriter(FW_Byte * buffer, FW_ByteCount capacity);
-
- protected:
-
- virtual void DoFlushAndGetNextBuffer();
-
- };
-
- //========================================================================================
- // CLASS FW_CTextReader
- //========================================================================================
-
- //----------------------------------------------------------------------------------------
- // FW_CTextReader::GetLength
- //----------------------------------------------------------------------------------------
-
- inline FW_CharacterCount FW_CTextReader::GetLength()
- {
- return fLength;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CTextReader::PeekRunAhead
- //----------------------------------------------------------------------------------------
-
- inline void FW_CTextReader::PeekRunAhead(const FW_Byte*& start,
- FW_ByteCount& length)
- {
- start = fNext;
- length = fLimit-fNext;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CTextReader::PeekRunBehind
- //----------------------------------------------------------------------------------------
-
- inline void FW_CTextReader::PeekRunBehind(const FW_Byte*& end,
- FW_ByteCount& length)
- {
- end = fNext;
- length = fNext-fStart;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CTextReader::Advance
- //----------------------------------------------------------------------------------------
-
- inline void FW_CTextReader::Advance()
- {
- ClassInvariants();
- #ifdef FW_VARIABLE_WIDTH_CHARACTERS
- fNext += BytesInString(fNext, 1);
- #else
- fNext += sizeof(FW_Char);
- #endif
- if (fNext == fLimit)
- GetNextBuffer();
- ClassInvariants();
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CTextReader::Backup
- //----------------------------------------------------------------------------------------
-
- inline void FW_CTextReader::Backup()
- {
- ClassInvariants();
- if (fNext == fStart)
- GetPreviousBuffer();
- #ifdef FW_VARIABLE_WIDTH_CHARACTERS
- NotYetImplemented();
- #else
- fNext -= sizeof(FW_Char);
- #endif
- ClassInvariants();
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CTextReader::PeekCharacter
- //----------------------------------------------------------------------------------------
-
- inline FW_Char FW_CTextReader::PeekCharacter()
- {
- ClassInvariants();
- if (fNext>=fStart && fNext<fLimit)
- {
- #ifdef FW_VARIABLE_WIDTH_CHARACTERS
- return NotYetImplemented();
- #else
- return *((FW_Char*)fNext);
- #endif
- }
- else
- return FW_kNulCharacter;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CTextReader::GetCharacterAndAdvance
- //----------------------------------------------------------------------------------------
-
- inline FW_Char FW_CTextReader::GetCharacterAndAdvance()
- {
- ClassInvariants();
- register FW_Char temp = PeekCharacter();
- if (temp!=FW_kNulCharacter)
- Advance();
- ClassInvariants();
- return temp;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CTextReader::BackupAndGetCharacter
- //----------------------------------------------------------------------------------------
-
- inline FW_Char FW_CTextReader::BackupAndGetCharacter()
- {
- ClassInvariants();
- Backup();
- ClassInvariants();
- return PeekCharacter();
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CTextReader::GetPosition
- //----------------------------------------------------------------------------------------
-
- inline FW_CharacterCount FW_CTextReader::GetPosition()
- {
- ClassInvariants();
- if (fNext == fLimit)
- return fBufferSum;
- else
- return fBufferSum + FW_CharactersInBlock(fStart, fNext - fStart);
- }
-
- //========================================================================================
- // CLASS FW_CTextWriter
- //========================================================================================
-
- //----------------------------------------------------------------------------------------
- // FW_CTextWriter::PutCharacterAndAdvance
- //----------------------------------------------------------------------------------------
-
- inline void FW_CTextWriter::PutCharacterAndAdvance(FW_Char character)
- {
- if (fNext >= fLimit)
- FlushAndGetNextBuffer();
- #ifdef FW_VARIABLE_WIDTH_CHARACTERS
- NotYetImplemented();
- #else
- *((FW_Char*)fNext) = character;
- fNext += sizeof(FW_Char);
- #endif
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CTextWriter::GetPosition
- //----------------------------------------------------------------------------------------
-
- inline FW_CharacterCount FW_CTextWriter::GetPosition()
- {
- return fBufferSum + FW_CharactersInBlock(fStart, fStart-fNext);
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CTextWriter::FlushAndGetNextBuffer
- //----------------------------------------------------------------------------------------
-
- inline void FW_CTextWriter::FlushAndGetNextBuffer()
- {
- fBufferSum += FW_CharactersInBlock(fStart, fStart-fNext);
- DoFlushAndGetNextBuffer();
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CTextWriter::WritePeek
- //----------------------------------------------------------------------------------------
-
- inline void FW_CTextWriter::WritePeek(FW_Byte*& start,
- FW_ByteCount& length)
- {
- if (fNext >= fLimit)
- FlushAndGetNextBuffer();
- start = fNext;
- length = fLimit-fNext;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CTextWriter::WritePeekAdvance
- //----------------------------------------------------------------------------------------
-
- inline void FW_CTextWriter::WritePeekAdvance(FW_Byte * const start,
- FW_ByteCount bytesWritten)
- {
- FW_ASSERT(start == fNext);
- FW_ASSERT(bytesWritten <= fLimit-fNext);
- fNext += bytesWritten;
- }
-
-
- #endif
-